package zlmedia_sdk

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"go.uber.org/zap/zapcore"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/google/go-querystring/query"
)

//doc: https://github.com/zlmediakit/ZLMediaKit/wiki/MediaServer%E6%94%AF%E6%8C%81%E7%9A%84HTTP-API

type Config struct {
	Endpoint string        `help:"接口地址" default:"http://127.0.0.1:81"`
	Secret   string        `help:"接口密钥，如果操作ip是127.0.0.1，则不需要此参数" default:""`
	Timeout  time.Duration `help:"超时时间" default:"30s"`
}

type ZLMediaClient struct {
	baseUrl string
	timeout time.Duration
	secret  string
}

type ZLMediaRequest interface {
	api() string
}

type ZLMediaResponse interface {
	Success() bool
	ErrMsg() string
}

type ResCommon struct {
	Code   int    `json:"code"`
	Msg    string `json:"msg,omitempty"`
	Result int    `json:"result,omitempty"`
}

func (receiver ResCommon) Success() bool {
	return receiver.Code == 0
}

func (receiver ResCommon) ErrMsg() string {
	if receiver.Result != 0 {
		return fmt.Sprintf("%s:[%d]", receiver.Msg, receiver.Result)
	}
	return receiver.Msg
}

func (receiver ResCommon) MarshalLogObject(enc zapcore.ObjectEncoder) error {
	enc.AddInt("code", receiver.Code)
	enc.AddString("msg", receiver.Msg)
	enc.AddInt("result", receiver.Result)
	return nil
}

func NewZLMediaClient(conf *Config) *ZLMediaClient {
	client := &ZLMediaClient{
		baseUrl: strings.TrimSuffix(conf.Endpoint, "/"),
		timeout: conf.Timeout,
		secret:  conf.Secret,
	}
	if client.timeout == 0 {
		client.timeout = time.Second * 10
	}
	return client
}

func (c *ZLMediaClient) Request(req ZLMediaRequest, res ZLMediaResponse) error {
	body, err := c.request(req)
	if err != nil {
		return err
	}
	return json.Unmarshal(body, &res)
}

func (c *ZLMediaClient) post(req ZLMediaRequest) (body []byte, err error) {
	httpClient := http.Client{Timeout: c.timeout}
	params, err := json.Marshal(req)
	if err != nil {
		return
	}
	resp, err := httpClient.Post(c.baseUrl+req.api(), "Content-Type:application/json", bytes.NewReader(params))
	if err != nil {
		return
	}
	if resp.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("request httpCode error:[%d]", resp.StatusCode))
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	return io.ReadAll(resp.Body)
}

func (c *ZLMediaClient) request(req ZLMediaRequest) (body []byte, err error) {
	httpClient := http.Client{Timeout: c.timeout}
	val, err := query.Values(req)
	if err != nil {
		return
	}
	if c.secret != "" {
		val.Set("secret", c.secret)
	}
	resp, err := httpClient.Get(fmt.Sprintf("%s%s?%s", c.baseUrl, req.api(), val.Encode()))
	if err != nil {
		return
	}
	if resp.StatusCode != 200 {
		return nil, errors.New(fmt.Sprintf("request httpCode error:[%d]", resp.StatusCode))
	}
	defer func() {
		_ = resp.Body.Close()
	}()
	return io.ReadAll(resp.Body)
}

func (c *ZLMediaClient) getApiUrl(api string) string {
	return c.baseUrl + api
}
